﻿using System;
using WeDonekRpc.Helper;
using WeDonekRpc.Helper.Json;
using StackExchange.Redis;

namespace WeDonekRpc.CacheClient.Redis
{
    internal class RedisTools
    {
        public static bool GetT<T> (RedisValue value, out T data)
        {
            if (!value.HasValue || value.IsNull)
            {
                data = default;
                return false;
            }
            else
            {
                data = RedisTools.GetResult<T>(value);
                return true;
            }
        }
        public static bool GetT<T> (RedisValue[] value, out T[] data)
        {
            if (value == null || value.Length == 0)
            {
                data = null;
                return false;
            }
            data = value.ConvertAll(a =>
            {
                return RedisTools.GetResult<T>(a);
            });
            return true;
        }
        public static T GetLuaResult<T> (RedisResult result)
        {
            if (result.Type == ResultType.MultiBulk)
            {
                throw new ErrorException("cache.redis.not.supported.format");
            }
            else if (result.Type == ResultType.Integer)
            {
                return (T)Convert.ChangeType(( (RedisValue)result ).Box(), typeof(T));
            }
            return _GetLuaResult<T>((RedisValue)result);
        }
        private static T _GetLuaResult<T> (RedisValue value)
        {
            Type type = typeof(T);
            if (type.FullName == PublicDataDic.GuidType.FullName)
            {
                object obj = new Guid(value.ToString());
                return (T)obj;
            }
            else if (type.FullName == PublicDataDic.UriType.FullName)
            {
                object obj = new Uri(value.ToString());
                return (T)obj;
            }
            else if (type.FullName == PublicDataDic.DateTimeType.FullName)
            {
                object obj = DateTime.Parse(value.ToString());
                return (T)obj;
            }
            else if (type.IsClass)
            {
                string json = value.ToString();
                if (type.Name == PublicDataDic.StringTypeName)
                {
                    object obj = json;
                    return (T)obj;
                }
                else
                {
                    return JsonTools.Json<T>(json);
                }
            }
            else if (type.IsEnum)
            {
                int val = (int)Convert.ChangeType(value, typeof(int));
                return EnumHelper.ToObject<T>(val);
            }
            else
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
        }
        public static T GetResult<T> (RedisValue value)
        {
            if (value.IsInteger)
            {
                return (T)Convert.ChangeType(value.Box(), typeof(T));
            }
            Type type = typeof(T);
            if (type.FullName == PublicDataDic.GuidType.FullName)
            {
                object obj = new Guid(value.ToString());
                return (T)obj;
            }
            else if (type.FullName == PublicDataDic.UriType.FullName)
            {
                object obj = new Uri(value.ToString());
                return (T)obj;
            }
            else if (type.FullName == PublicDataDic.DateTimeType.FullName)
            {
                object obj = DateTime.Parse(value.ToString());
                return (T)obj;
            }
            else if (type.IsClass)
            {
                if (type.Name == PublicDataDic.StringTypeName)
                {
                    object obj = value.ToString();
                    return (T)obj;
                }
                else
                {
                    return ZipTools.DecompressionObject<T>((byte[])value);
                }
            }
            else if (type.IsEnum)
            {
                int val = (int)Convert.ChangeType(value, typeof(int));
                return EnumHelper.ToObject<T>(val);
            }
            else
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
        }
        public static RedisValue Serializable<T> (T data)
        {
            Type type = typeof(T);
            if (type.FullName == PublicDataDic.GuidType.FullName)
            {
                return RedisValue.Unbox(data.ToString());
            }
            else if (type.FullName == PublicDataDic.UriType.FullName)
            {
                return RedisValue.Unbox(data.ToString());
            }
            else if (type.FullName == PublicDataDic.DateTimeType.FullName)
            {
                return RedisValue.Unbox(data.ToString());
            }
            return type.IsClass && type.Name != PublicDataDic.StringTypeName ? ZipTools.CompressionObject<T>(data) : RedisValue.Unbox(data);
        }
    }
}
